//TIP 要<b>运行</b>代码，请按 <shortcut actionId="Run"/> 或
// 点击装订区域中的 <icon src="AllIcons.Actions.Execute"/> 图标。
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.io.*;
// 枚举类型定义
enum UserType { ADMIN, MANAGER, FRONT_DESK }
enum SeatStatus { AVAILABLE, OCCUPIED }

// 用户基类
class User {
    private final String userId;
    private final String username;
    private String password;
    private final LocalDateTime registerTime;
    private String phone;
    private final UserType userType;

    public User(String userId, String username, String password, String phone, UserType userType) {
        this.userId = userId;
        this.username = username;
        this.password = password;
        this.registerTime = LocalDateTime.now();
        this.phone = phone;
        this.userType = userType;
    }

    public boolean changePassword(String oldPassword, String newPassword) {
        if (this.password.equals(oldPassword)) {
            this.password = newPassword;
            Logger.log("修改密码", this.username);
            return true;
        }
        return false;
    }

    public void resetPassword() {
        this.password = "123456";
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    // Getters
    public String getUserId() { return userId; }
    public String getUsername() { return username; }
    public String getPassword() { return password; }
    public LocalDateTime getRegisterTime() { return registerTime; }
    public String getPhone() { return phone; }
    public UserType getUserType() { return userType; }
}

// 管理员类
class Admin extends User {
    public Admin(String userId, String username, String password, String phone) {
        super(userId, username, password, phone, UserType.ADMIN);
    }

    public void addUser(List<User> users, User newUser) {
        boolean exists = users.stream().anyMatch(u ->
                u.getUserId().equals(newUser.getUserId()) ||
                        u.getUsername().equals(newUser.getUsername()) ||
                        u.getPhone().equals(newUser.getPhone()));

        if (!exists) {
            users.add(newUser);
            Logger.log("添加用户: " + newUser.getUsername(), this.getUsername());
        }
    }

    public boolean deleteUser(List<User> users, String userId) {
        if ("admin".equals(userId)) {
            System.out.println("不能删除admin账户");
            return false;
        }

        Iterator<User> iterator = users.iterator();
        while (iterator.hasNext()) {
            User user = iterator.next();
            if (user.getUserId().equals(userId)) {
                iterator.remove();
                Logger.log("删除用户: " + user.getUsername(), this.getUsername());
                return true;
            }
        }
        return false;
    }

    public void resetUserPassword(User user) {
        if (!(user instanceof Admin)) {
            user.resetPassword();
            Logger.log("重置密码: " + user.getUsername(), this.getUsername());
        }
    }
}

// 经理类
class Manager extends User {
    public Manager(String userId, String username, String password, String phone) {
        super(userId, username, password, phone, UserType.MANAGER);
    }

    public void resetFrontDeskPassword(FrontDesk user) {
        user.resetPassword();
        Logger.log("重置前台密码: " + user.getUsername(), this.getUsername());
    }

    // 添加影片
    public void addMovie(List<Movie> movies, Movie movie) {
        movies.add(movie);
        Logger.log("添加电影: " + movie.getTitle(), this.getUsername());
    }
}

// 前台类
class FrontDesk extends User {
    public FrontDesk(String userId, String username, String password, String phone) {
        super(userId, username, password, phone, UserType.FRONT_DESK);
    }
}

// 电影类
class Movie {
    private final String movieId;
    private String title;
    private String director;
    private List<String> actors;
    private String plot;
    private int duration;
    private double rating;

    public Movie(String movieId, String title, String director, List<String> actors, String plot, int duration, double rating) {
        this.movieId = movieId;
        this.title = title;
        this.director = director;
        this.actors = actors;
        this.plot = plot;
        this.duration = duration;
        this.rating = rating;
    }

    public String getMovieId() { return movieId; }
    public String getTitle() { return title; }
    public void setTitle(String title) { this.title = title; }
    public String getDirector() { return director; }
    public void setDirector(String director) { this.director = director; }
    public List<String> getActors() { return actors; }
    public void setActors(List<String> actors) { this.actors = actors; }
    public String getPlot() { return plot; }
    public void setPlot(String plot) { this.plot = plot; }
    public int getDuration() { return duration; }
    public void setDuration(int duration) { this.duration = duration; }
    public double getRating() { return rating; }
    public void setRating(double rating) { this.rating = rating; }
}

// 放映厅类
class ScreeningRoom {
    private final String roomId;
    private final String name;
    private final int rows;
    private final int columns;
    private Seat[][] seats;

    public ScreeningRoom(String roomId, String name, int rows, int columns) {
        this.roomId = roomId;
        this.name = name;
        this.rows = rows;
        this.columns = columns;
        initializeSeats();
    }

    private void initializeSeats() {
        seats = new Seat[rows][columns];
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < columns; j++) {
                seats[i][j] = new Seat(i + 1, j + 1);
            }
        }
    }

    public String getSeatLayout() {
        StringBuilder sb = new StringBuilder();
        sb.append("   ");
        for (int j = 0; j < columns; j++) {
            sb.append(String.format("%-4d", j + 1));
        }
        sb.append("\n");

        for (int i = 0; i < rows; i++) {
            sb.append(String.format("%-3d", i + 1));
            for (int j = 0; j < columns; j++) {
                sb.append(seats[i][j].getStatus() == SeatStatus.AVAILABLE ? "O   " : "X   ");
            }
            sb.append("\n");
        }
        return sb.toString();
    }

    public int getAvailableSeats() {
        int count = 0;
        for (Seat[] row : seats) {
            for (Seat seat : row) {
                if (seat.getStatus() == SeatStatus.AVAILABLE) {
                    count++;
                }
            }
        }
        return count;
    }

    public Seat getSeat(int row, int col) {
        if (row > 0 && row <= rows && col > 0 && col <= columns) {
            return seats[row - 1][col - 1];
        }
        return null;
    }

    // Getters
    public String getRoomId() { return roomId; }
    public String getName() { return name; }
    public int getRows() { return rows; }
    public int getColumns() { return columns; }
}

// 座位类
class Seat {
    private final int row;
    private final int column;
    private SeatStatus status;

    public Seat(int row, int column) {
        this.row = row;
        this.column = column;
        this.status = SeatStatus.AVAILABLE;
    }

    public void occupy() {
        this.status = SeatStatus.OCCUPIED;
    }

    public void release() {
        this.status = SeatStatus.AVAILABLE;
    }

    // Getters
    public int getRow() { return row; }
    public int getColumn() { return column; }
    public SeatStatus getStatus() { return status; }
}

// 场次类
class Screening {
    private final String screeningId;
    private Movie movie;
    private ScreeningRoom room;
    private LocalDateTime startTime;
    private double price;
    private final List<Ticket> tickets = new ArrayList<>();

    public Screening(String screeningId, Movie movie, ScreeningRoom room, LocalDateTime startTime, double price) {
        this.screeningId = screeningId;
        this.movie = movie;
        this.room = room;
        this.startTime = startTime;
        this.price = price;
    }

    public Ticket sellTicket(int row, int col) {
        Seat seat = room.getSeat(row, col);
        if (seat != null && seat.getStatus() == SeatStatus.AVAILABLE) {
            seat.occupy();
            Ticket ticket = new Ticket(this, row, col);
            tickets.add(ticket);
            return ticket;
        }
        return null;
    }

    public boolean refundTicket(String ticketId) {
        Iterator<Ticket> iterator = tickets.iterator();
        while (iterator.hasNext()) {
            Ticket ticket = iterator.next();
            if (ticket.getTicketId().equals(ticketId)) {
                Seat seat = room.getSeat(ticket.getRow(), ticket.getColumn());
                if (seat != null) {
                    seat.release();
                }
                iterator.remove();
                return true;
            }
        }
        return false;
    }

    public boolean hasSoldTickets() {
        return !tickets.isEmpty();
    }

    public String getScreeningId() { return screeningId; }
    public Movie getMovie() { return movie; }
    public void setMovie(Movie movie) { this.movie = movie; }
    public ScreeningRoom getRoom() { return room; }
    public void setRoom(ScreeningRoom room) { this.room = room; }
    public LocalDateTime getStartTime() { return startTime; }
    public void setStartTime(LocalDateTime startTime) { this.startTime = startTime; }
    public double getPrice() { return price; }
    public void setPrice(double price) { this.price = price; }
    public List<Ticket> getTickets() { return tickets; }
}

// 电影票类
class Ticket {
    private final String ticketId;
    private final Screening screening;
    private final int row;
    private final int column;
    private final LocalDateTime purchaseTime;
    private final double price;

    public Ticket(Screening screening, int row, int column) {
        this.ticketId = UUID.randomUUID().toString();
        this.screening = screening;
        this.row = row;
        this.column = column;
        this.purchaseTime = LocalDateTime.now();
        this.price = screening.getPrice();
    }

    // Getters
    public String getTicketId() { return ticketId; }
    public Screening getScreening() { return screening; }
    public int getRow() { return row; }
    public int getColumn() { return column; }
    public LocalDateTime getPurchaseTime() { return purchaseTime; }
    public double getPrice() { return price; }
}

// 日志工具类
class Logger {
    private static final String LOG_FILE = "cinema_system.log";
    private static final DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    public static void log(String actionType, String operator) {
        String logEntry = String.format("[%s] [%s] [%s]%n",
                LocalDateTime.now().format(dtf),
                operator,
                actionType);

        try (FileWriter fw = new FileWriter(LOG_FILE, true);
             BufferedWriter bw = new BufferedWriter(fw);
             PrintWriter out = new PrintWriter(bw)) {
            out.println(logEntry);
        } catch (IOException e) {
            System.out.println("日志写入失败: " + e.getMessage());
        }
    }
}

// 数据持久化管理
class DataManager {
    private static final String USER_FILE = "users.dat";
    private static final String MOVIE_FILE = "movies.dat";
    private static final String ROOM_FILE = "rooms.dat";
    private static final String SCREENING_FILE = "screenings.dat";

    public static void saveData(List<User> users, List<Movie> movies,
                                List<ScreeningRoom> rooms, List<Screening> screenings) {
        saveObject(users, USER_FILE);
        saveObject(movies, MOVIE_FILE);
        saveObject(rooms, ROOM_FILE);
        saveObject(screenings, SCREENING_FILE);
    }

    @SuppressWarnings("unchecked")
    public static void loadData(List<User> users, List<Movie> movies,
                                List<ScreeningRoom> rooms, List<Screening> screenings) {
        users.addAll((List<User>) loadObject(USER_FILE));
        movies.addAll((List<Movie>) loadObject(MOVIE_FILE));
        rooms.addAll((List<ScreeningRoom>) loadObject(ROOM_FILE));
        screenings.addAll((List<Screening>) loadObject(SCREENING_FILE));
    }

    private static void saveObject(Object obj, String filename) {
        try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filename))) {
            oos.writeObject(obj);
        } catch (IOException e) {
            System.out.println("数据保存失败: " + e.getMessage());
        }
    }

    private static Object loadObject(String filename) {
        try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filename))) {
            return ois.readObject();
        } catch (IOException | ClassNotFoundException e) {
            System.out.println("数据加载失败: " + e.getMessage());
            return new ArrayList<>();
        }
    }
}

// 影院系统主类
public class CinemaSystem {
    private static final Scanner scanner = new Scanner(System.in);
    private static final List<User> users = new ArrayList<>();
    private static final List<Movie> movies = new ArrayList<>();
    private static final List<ScreeningRoom> rooms = new ArrayList<>();
    private static final List<Screening> screenings = new ArrayList<>();
    private static User currentUser = null;

    public static void main(String[] args) {
        loadData();
        if (users.isEmpty()) {
            initializeData();
        }
        showMainMenu();
    }

    private static void initializeData() {
        users.add(new Admin("admin001", "admin", "ynuinfo#777", "13800138000"));
        rooms.add(new ScreeningRoom("gold", "黄金厅", 8, 10));
        rooms.add(new ScreeningRoom("silver", "白银厅", 10, 12));
        rooms.add(new ScreeningRoom("jade", "翡翠厅", 7, 8));
        rooms.add(new ScreeningRoom("diamond", "钻石厅", 7, 8));
        rooms.add(new ScreeningRoom("gem", "宝石厅", 8, 9));
        saveData();
    }

    private static void saveData() {
        DataManager.saveData(users, movies, rooms, screenings);
    }

    private static void loadData() {
        DataManager.loadData(users, movies, rooms, screenings);
    }

    private static void showMainMenu() {
        while (true) {
            System.out.println("\n=== 万东影院管理系统 ===");
            System.out.println("1. 登录");
            System.out.println("2. 退出系统");
            System.out.print("请选择: ");

            int choice = readInt();
            switch (choice) {
                case 1 -> login();
                case 2 -> {
                    saveData();
                    System.out.println("系统已退出");
                    return;
                }
                default -> System.out.println("无效选择，请重新输入");
            }
        }
    }

    private static void login() {
        System.out.print("用户名: ");
        String username = scanner.nextLine();
        System.out.print("密码: ");
        String password = scanner.nextLine();

        for (User user : users) {
            if (user.getUsername().equals(username) && user.getPassword().equals(password)) {
                currentUser = user;
                System.out.println("登录成功! 欢迎 " + username);
                redirectToUserMenu();
                return;
            }
        }
        System.out.println("用户名或密码错误");
    }

    private static void redirectToUserMenu() {
        if (currentUser instanceof Admin) {
            showAdminMenu();
        } else if (currentUser instanceof Manager) {
            showManagerMenu();
        } else if (currentUser instanceof FrontDesk) {
            showFrontDeskMenu();
        }
    }

    // 管理员菜单功能
    private static void showAdminMenu() {
        Admin admin = (Admin) currentUser;
        while (true) {
            System.out.println("\n=== 管理员菜单 ===");
            System.out.println("1. 用户管理");
            System.out.println("2. 修改密码");
            System.out.println("3. 退出登录");
            System.out.print("请选择: ");

            int choice = readInt();
            switch (choice) {
                case 1 -> userManagement(admin);
                case 2 -> changePassword(admin);
                case 3 -> {
                    currentUser = null;
                    return;
                }
                default -> System.out.println("无效选择");
            }
        }
    }

    private static void userManagement(Admin admin) {
        while (true) {
            System.out.println("\n=== 用户管理 ===");
            System.out.println("1. 添加用户");
            System.out.println("2. 删除用户");
            System.out.println("3. 重置密码");
            System.out.println("4. 返回上级");
            System.out.print("请选择: ");

            int choice = readInt();
            switch (choice) {
                case 1 -> addUser(admin);
                case 2 -> deleteUser(admin);
                case 3 -> resetPassword(admin);
                case 4 -> { return; }
                default -> System.out.println("无效选择");
            }
        }
    }

    private static void addUser(Admin admin) {
        System.out.print("用户ID: ");
        String userId = scanner.nextLine();
        System.out.print("用户名: ");
        String username = scanner.nextLine();
        System.out.print("手机号: ");
        String phone = scanner.nextLine();

        System.out.println("选择用户类型: ");
        System.out.println("1. 管理员");
        System.out.println("2. 经理");
        System.out.println("3. 前台");
        System.out.print("请选择: ");
        int typeChoice = readInt();

        UserType userType = switch (typeChoice) {
            case 1 -> UserType.ADMIN;
            case 2 -> UserType.MANAGER;
            case 3 -> UserType.FRONT_DESK;
            default -> UserType.FRONT_DESK;
        };

        User newUser;
        if (userType == UserType.ADMIN) {
            newUser = new Admin(userId, username, "123456", phone);
        } else if (userType == UserType.MANAGER) {
            newUser = new Manager(userId, username, "123456", phone);
        } else {
            newUser = new FrontDesk(userId, username, "123456", phone);
        }

        admin.addUser(users, newUser);
        System.out.println("用户添加成功!");
    }

    private static void deleteUser(Admin admin) {
        System.out.print("输入要删除的用户ID: ");
        String userId = scanner.nextLine();
        if (admin.deleteUser(users, userId)) {
            System.out.println("用户删除成功");
        } else {
            System.out.println("用户删除失败");
        }
    }

    private static void resetPassword(Admin admin) {
        System.out.print("输入要重置密码的用户ID: ");
        String userId = scanner.nextLine();
        for (User user : users) {
            if (user.getUserId().equals(userId)) {
                admin.resetUserPassword(user);
                System.out.println("密码重置成功");
                return;
            }
        }
        System.out.println("未找到用户");
    }

    private static void changePassword(User user) {
        System.out.print("输入旧密码: ");
        String oldPwd = scanner.nextLine();
        System.out.print("输入新密码: ");
        String newPwd = scanner.nextLine();

        if (user.changePassword(oldPwd, newPwd)) {
            System.out.println("密码修改成功");
        } else {
            System.out.println("密码修改失败");
        }
    }

    // 经理菜单功能
    private static void showManagerMenu() {
        Manager manager = (Manager) currentUser;
        while (true) {
            System.out.println("\n=== 经理菜单 ===");
            System.out.println("1. 影片管理");
            System.out.println("2. 修改密码");
            System.out.println("3. 退出登录");
            System.out.print("请选择: ");

            int choice = readInt();
            switch (choice) {
                case 1 -> movieManagement(manager);
                case 2 -> changePassword(manager);
                case 3 -> {
                    currentUser = null;
                    return;
                }
                default -> System.out.println("无效选择");
            }
        }
    }

    private static void movieManagement(Manager manager) {
        while (true) {
            System.out.println("\n=== 影片管理 ===");
            System.out.println("1. 添加影片");
            System.out.println("2. 列出所有影片");
            System.out.println("3. 返回上级");
            System.out.print("请选择: ");

            int choice = readInt();
            switch (choice) {
                case 1 -> addMovie(manager);
                case 2 -> listMovies();
                case 3 -> { return; }
                default -> System.out.println("无效选择");
            }
        }
    }

    private static void addMovie(Manager manager) {
        System.out.print("电影ID: ");
        String movieId = scanner.nextLine();
        System.out.print("片名: ");
        String title = scanner.nextLine();
        System.out.print("导演: ");
        String director = scanner.nextLine();

        System.out.println("主演(用逗号分隔): ");
        String actorsInput = scanner.nextLine();
        List<String> actors = Arrays.asList(actorsInput.split(","));

        System.out.print("剧情简介: ");
        String plot = scanner.nextLine();
        System.out.print("时长(分钟): ");
        int duration = readInt();
        System.out.print("评分(0-10): ");
        double rating = readDouble();

        Movie movie = new Movie(movieId, title, director, actors, plot, duration, rating);
        manager.addMovie(movies, movie);
        System.out.println("电影添加成功!");
    }

    private static void listMovies() {
        System.out.println("\n=== 所有影片 ===");
        for (Movie movie : movies) {
            System.out.println("ID: " + movie.getMovieId());
            System.out.println("片名: " + movie.getTitle());
            System.out.println("导演: " + movie.getDirector());
            System.out.println("主演: " + String.join(", ", movie.getActors()));
            System.out.println("时长: " + movie.getDuration() + "分钟");
            System.out.println("评分: " + movie.getRating());
            System.out.println("----------------------");
        }
    }

    // 前台菜单功能
    private static void showFrontDeskMenu() {
        FrontDesk frontDesk = (FrontDesk) currentUser;
        while (true) {
            System.out.println("\n=== 前台菜单 ===");
            System.out.println("1. 售票");
            System.out.println("2. 退票");
            System.out.println("3. 修改密码");
            System.out.println("4. 退出登录");
            System.out.print("请选择: ");

            int choice = readInt();
            switch (choice) {
                case 1 -> sellTicket();
                case 2 -> refundTicket();
                case 3 -> changePassword(frontDesk);
                case 4 -> {
                    currentUser = null;
                    return;
                }
                default -> System.out.println("无效选择");
            }
        }
    }

    private static void sellTicket() {
        System.out.println("=== 售票功能 ===");
        listMovies();

        System.out.print("选择电影ID: ");
        String movieId = scanner.nextLine();
        Movie selectedMovie = null;
        for (Movie movie : movies) {
            if (movie.getMovieId().equals(movieId)) {
                selectedMovie = movie;
                break;
            }
        }

        if (selectedMovie == null) {
            System.out.println("未找到电影");
            return;
        }

        System.out.println("可选场次:");
        for (Screening screening : screenings) {
            if (screening.getMovie().getMovieId().equals(movieId)) {
                System.out.println("场次ID: " + screening.getScreeningId() +
                        " 时间: " + screening.getStartTime() +
                        " 影厅: " + screening.getRoom().getName());
            }
        }

        System.out.print("输入场次ID: ");
        String screeningId = scanner.nextLine();
        Screening selectedScreening = null;
        for (Screening screening : screenings) {
            if (screening.getScreeningId().equals(screeningId)) {
                selectedScreening = screening;
                break;
            }
        }

        if (selectedScreening == null) {
            System.out.println("未找到场次");
            return;
        }

        System.out.println("座位布局:");
        System.out.println(selectedScreening.getRoom().getSeatLayout());

        System.out.print("输入座位行号: ");
        int row = readInt();
        System.out.print("输入座位列号: ");
        int col = readInt();

        Ticket ticket = selectedScreening.sellTicket(row, col);
        if (ticket != null) {
            System.out.println("\n=== 售票成功 ===");
            System.out.println("电影: " + selectedMovie.getTitle());
            System.out.println("场次: " + selectedScreening.getStartTime());
            System.out.println("影厅: " + selectedScreening.getRoom().getName());
            System.out.println("座位: " + row + "排" + col + "座");
            System.out.println("票号: " + ticket.getTicketId());
            System.out.println("价格: " + ticket.getPrice());
            System.out.println("=================");
        } else {
            System.out.println("售票失败，座位不可用");
        }
    }

    private static void refundTicket() {
        System.out.print("输入要退的票号: ");
        String ticketId = scanner.nextLine();

        for (Screening screening : screenings) {
            if (screening.refundTicket(ticketId)) {
                System.out.println("退票成功");
                return;
            }
        }
        System.out.println("退票失败，未找到票号");
    }

    // 工具方法
    private static int readInt() {
        while (true) {
            try {
                return Integer.parseInt(scanner.nextLine());
            } catch (NumberFormatException e) {
                System.out.print("输入无效，请重新输入数字: ");
            }
        }
    }

    private static double readDouble() {
        while (true) {
            try {
                return Double.parseDouble(scanner.nextLine());
            } catch (NumberFormatException e) {
                System.out.print("输入无效，请重新输入数字: ");
            }
        }
    }
}